﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using FlickrNet;
using System.Xml;
using System.Xml.XPath;
using System.Collections.Specialized;
using System.Configuration;
using pwFlickrAPIConfig;

namespace ProWorks
{
    public class FlickrAPIExtensions
    {
        /// <summary>
        /// Use the Flickr API to search for all photos by a user
        /// </summary>
        /// <param name="flickrUserId">User Id from Flickr (i.e. 12345678@N12)</param>
        /// <param name="flickrSizeMSTB">
        /// s	small square 75x75
        /// t	thumbnail, 100 on longest side
        /// m	small, 240 on longest side
        /// -	medium, 500 on longest side (default)
        /// b	large, 1024 on longest side (only exists for very large original images)
        /// </param>
        /// <param name="flickrThumbSizeMSTB">
        /// s	small square 75x75
        /// t	thumbnail, 100 on longest side
        /// </param>
        /// <param name="numberOfPhotos">Integer. The maximum allowed value is 500.</param>
        /// <param name="flickrSortOrder">The possible values are: date-posted-asc, date-posted-desc, date-taken-asc, date-taken-desc, interestingness-desc (default), interestingness-asc, and relevance</param>
        /// <param name="minTakenDate">Minimum taken date. Photos with an taken date greater than or equal to this value will be returned.</param>
        /// <param name="maxTakenDate">Maximum taken date. Photos with an taken date less than or equal to this value will be returned.</param>
        /// <returns>XML</returns>
        public static XPathNodeIterator ByUser(string flickrUserId, string flickrSizeMSTB, string flickrThumbSizeMSTB, int numberOfPhotos, string flickrSortOrder, string minTakenDate, string maxTakenDate)
        {
            try
            {
                //Create XML object
                XmlDocument doc = new XmlDocument();
                XmlElement PhotoList = (XmlElement)doc.AppendChild(doc.CreateElement("PhotoList"));

                // Setup Search
                Flickr flickr = new Flickr();

                PhotoSearchOptions searchOptions = new PhotoSearchOptions();
                searchOptions.UserId = flickrUserId;
                searchOptions.SafeSearch = SafetyLevel.Safe;
                searchOptions.PerPage = numberOfPhotos;
                searchOptions.Extras = (PhotoSearchExtras.DateTaken | PhotoSearchExtras.Geo | PhotoSearchExtras.OwnerName | PhotoSearchExtras.Tags | PhotoSearchExtras.Views);
                searchOptions.SortOrder = PhotoSearchSortOrder.InterestingnessDescending;
                if (!string.IsNullOrEmpty(flickrSortOrder))
                {
                    searchOptions.SortOrder = SearchOrderFromString(flickrSortOrder);
                }
                DateTime minTaken;
                if (DateTime.TryParse(minTakenDate, out minTaken))
                {
                    searchOptions.MinTakenDate = minTaken;
                }
                DateTime maxTaken;
                if (DateTime.TryParse(maxTakenDate, out maxTaken))
                {
                    searchOptions.MaxTakenDate = maxTaken;
                }

                // Call Flickr API
                var flickrPhotos = flickr.PhotosSearch(searchOptions);

                // Build XML to return
                foreach (var photo in flickrPhotos)
                {
                    PhotoList.AppendChild(BuildSinglePhotoXml(photo, doc, flickrSizeMSTB, flickrThumbSizeMSTB));
                }

                return doc.CreateNavigator().Select("/*");
            }
            catch (Exception e)
            {
                // If there's an exception we'll output an error element instead
                XmlDocument errorDoc = new XmlDocument();
                errorDoc.LoadXml(String.Format("<error>{0}</error>", System.Web.HttpUtility.HtmlEncode(e.ToString())));
                return errorDoc.CreateNavigator().Select(".");
            }
        }

        /// <summary>
        /// Use the Flickr API to search for all photos by a user.  This has Paging available to get more than 500 photos.
        /// </summary>
        /// <param name="flickrUserId">User Id from Flickr (i.e. 12345678@N12)</param>
        /// <param name="flickrSizeMSTB">
        /// s	small square 75x75
        /// t	thumbnail, 100 on longest side
        /// m	small, 240 on longest side
        /// -	medium, 500 on longest side (default)
        /// b	large, 1024 on longest side (only exists for very large original images)
        /// </param>
        /// <param name="flickrThumbSizeMSTB">
        /// s	small square 75x75
        /// t	thumbnail, 100 on longest side
        /// </param>
        /// <param name="photosPerPage">Integer. The maximum allowed value is 500.</param>
        /// <param name="page">Integer. The page of results to return.</param>
        /// <param name="flickrSortOrder">The possible values are: date-posted-asc, date-posted-desc, date-taken-asc, date-taken-desc, interestingness-desc (default), interestingness-asc, and relevance</param>
        /// <param name="minTakenDate">Minimum taken date. Photos with an taken date greater than or equal to this value will be returned.</param>
        /// <param name="maxTakenDate">Maximum taken date. Photos with an taken date less than or equal to this value will be returned.</param>
        /// <returns>XML</returns>
        public static XPathNodeIterator ByUserWithPaging(string flickrUserId, string flickrSizeMSTB, string flickrThumbSizeMSTB, int photosPerPage, int page, string flickrSortOrder, string minTakenDate, string maxTakenDate)
        {
            try
            {
                //Create XML object
                XmlDocument doc = new XmlDocument();
                XmlElement PhotoList = (XmlElement)doc.AppendChild(doc.CreateElement("PhotoList"));

                // Setup Search
                Flickr flickr = new Flickr();

                PhotoSearchOptions searchOptions = new PhotoSearchOptions();
                searchOptions.UserId = flickrUserId;
                searchOptions.SafeSearch = SafetyLevel.Safe;
                searchOptions.PerPage = photosPerPage;
                searchOptions.Page = page;
                searchOptions.Extras = (PhotoSearchExtras.DateTaken | PhotoSearchExtras.Geo | PhotoSearchExtras.OwnerName | PhotoSearchExtras.Tags | PhotoSearchExtras.Views);
                searchOptions.SortOrder = PhotoSearchSortOrder.InterestingnessDescending;
                if (!string.IsNullOrEmpty(flickrSortOrder))
                {
                    searchOptions.SortOrder = SearchOrderFromString(flickrSortOrder);
                }
                DateTime minTaken;
                if (DateTime.TryParse(minTakenDate, out minTaken))
                {
                    searchOptions.MinTakenDate = minTaken;
                }
                DateTime maxTaken;
                if (DateTime.TryParse(maxTakenDate, out maxTaken))
                {
                    searchOptions.MaxTakenDate = maxTaken;
                }

                // Call Flickr API
                var flickrPhotos = flickr.PhotosSearch(searchOptions);

                // Build XML to return
                foreach (var photo in flickrPhotos)
                {
                    PhotoList.AppendChild(BuildSinglePhotoXml(photo, doc, flickrSizeMSTB, flickrThumbSizeMSTB));
                }

                return doc.CreateNavigator().Select("/*");
            }
            catch (Exception e)
            {
                // If there's an exception we'll output an error element instead
                XmlDocument errorDoc = new XmlDocument();
                errorDoc.LoadXml(String.Format("<error>{0}</error>", System.Web.HttpUtility.HtmlEncode(e.ToString())));
                return errorDoc.CreateNavigator().Select(".");
            }
        }

        /// <summary>
        /// Use the Flickr API to search for all photos by a group id
        /// </summary>
        /// <param name="flickrGroupId">Group Id from Flickr (i.e. 12345678@N12)</param>
        /// <param name="flickrSizeMSTB">
        /// s	small square 75x75
        /// t	thumbnail, 100 on longest side
        /// m	small, 240 on longest side
        /// -	medium, 500 on longest side (default)
        /// b	large, 1024 on longest side (only exists for very large original images)
        /// </param>
        /// <param name="flickrThumbSizeMSTB">
        /// s	small square 75x75
        /// t	thumbnail, 100 on longest side
        /// </param>
        /// <param name="numberOfPhotos">Integer. The maximum allowed value is 500.</param>
        /// <param name="flickrSortOrder">The possible values are: date-posted-asc, date-posted-desc, date-taken-asc, date-taken-desc, interestingness-desc (default), interestingness-asc, and relevance</param>
        /// <param name="minTakenDate">Minimum taken date. Photos with an taken date greater than or equal to this value will be returned.</param>
        /// <param name="maxTakenDate">Maximum taken date. Photos with an taken date less than or equal to this value will be returned.</param>
        /// <returns>XML</returns>
        public static XPathNodeIterator ByGroup(string flickrGroupId, string flickrSizeMSTB, string flickrThumbSizeMSTB, int numberOfPhotos, string flickrSortOrder, string minTakenDate, string maxTakenDate)
        {
            try
            {
                //Create XML object
                XmlDocument doc = new XmlDocument();
                XmlElement PhotoList = (XmlElement)doc.AppendChild(doc.CreateElement("PhotoList"));

                // Setup Search
                Flickr flickr = new Flickr();

                PhotoSearchOptions searchOptions = new PhotoSearchOptions();
                searchOptions.GroupId = flickrGroupId;
                searchOptions.SafeSearch = SafetyLevel.Safe;
                searchOptions.PerPage = numberOfPhotos;
                searchOptions.Extras = (PhotoSearchExtras.DateTaken | PhotoSearchExtras.Geo | PhotoSearchExtras.OwnerName | PhotoSearchExtras.Tags | PhotoSearchExtras.Views);
                searchOptions.SortOrder = PhotoSearchSortOrder.InterestingnessDescending;
                if (!string.IsNullOrEmpty(flickrSortOrder))
                {
                    searchOptions.SortOrder = SearchOrderFromString(flickrSortOrder);
                }
                DateTime minTaken;
                if (DateTime.TryParse(minTakenDate, out minTaken))
                {
                    searchOptions.MinTakenDate = minTaken;
                }
                DateTime maxTaken;
                if (DateTime.TryParse(maxTakenDate, out maxTaken))
                {
                    searchOptions.MaxTakenDate = maxTaken;
                }

                // Call Flickr API
                var flickrPhotos = flickr.PhotosSearch(searchOptions);

                // Build XML to return
                foreach (var photo in flickrPhotos)
                {
                    PhotoList.AppendChild(BuildSinglePhotoXml(photo, doc, flickrSizeMSTB, flickrThumbSizeMSTB));
                }

                return doc.CreateNavigator().Select("/*");
            }
            catch (Exception e)
            {
                // If there's an exception we'll output an error element instead
                XmlDocument errorDoc = new XmlDocument();
                errorDoc.LoadXml(String.Format("<error>{0}</error>", System.Web.HttpUtility.HtmlEncode(e.ToString())));
                return errorDoc.CreateNavigator().Select(".");
            }
        }

        /// <summary>
        /// Use the Flickr API to search for all photos by a group id. This has Paging available to get more than 500 photos.
        /// </summary>
        /// <param name="flickrGroupId">Group Id from Flickr (i.e. 12345678@N12)</param>
        /// <param name="flickrSizeMSTB">
        /// s	small square 75x75
        /// t	thumbnail, 100 on longest side
        /// m	small, 240 on longest side
        /// -	medium, 500 on longest side (default)
        /// b	large, 1024 on longest side (only exists for very large original images)
        /// </param>
        /// <param name="flickrThumbSizeMSTB">
        /// s	small square 75x75
        /// t	thumbnail, 100 on longest side
        /// </param>
        /// <param name="photosPerPage">Integer. The maximum allowed value is 500.</param>
        /// <param name="page">Integer. The page of results to return.</param>
        /// <param name="flickrSortOrder">The possible values are: date-posted-asc, date-posted-desc, date-taken-asc, date-taken-desc, interestingness-desc (default), interestingness-asc, and relevance</param>
        /// <param name="minTakenDate">Minimum taken date. Photos with an taken date greater than or equal to this value will be returned.</param>
        /// <param name="maxTakenDate">Maximum taken date. Photos with an taken date less than or equal to this value will be returned.</param>
        /// <returns>XML</returns>
        public static XPathNodeIterator ByGroupWithPaging(string flickrGroupId, string flickrSizeMSTB, string flickrThumbSizeMSTB, int photosPerPage, int page, string flickrSortOrder, string minTakenDate, string maxTakenDate)
        {
            try
            {
                //Create XML object
                XmlDocument doc = new XmlDocument();
                XmlElement PhotoList = (XmlElement)doc.AppendChild(doc.CreateElement("PhotoList"));

                // Setup Search
                Flickr flickr = new Flickr();

                PhotoSearchOptions searchOptions = new PhotoSearchOptions();
                searchOptions.GroupId = flickrGroupId;
                searchOptions.SafeSearch = SafetyLevel.Safe;
                searchOptions.PerPage = photosPerPage;
                searchOptions.Page = page;
                searchOptions.Extras = (PhotoSearchExtras.DateTaken | PhotoSearchExtras.Geo | PhotoSearchExtras.OwnerName | PhotoSearchExtras.Tags | PhotoSearchExtras.Views);
                searchOptions.SortOrder = PhotoSearchSortOrder.InterestingnessDescending;
                if (!string.IsNullOrEmpty(flickrSortOrder))
                {
                    searchOptions.SortOrder = SearchOrderFromString(flickrSortOrder);
                }
                DateTime minTaken;
                if (DateTime.TryParse(minTakenDate, out minTaken))
                {
                    searchOptions.MinTakenDate = minTaken;
                }
                DateTime maxTaken;
                if (DateTime.TryParse(maxTakenDate, out maxTaken))
                {
                    searchOptions.MaxTakenDate = maxTaken;
                }

                // Call Flickr API
                var flickrPhotos = flickr.PhotosSearch(searchOptions);

                // Build XML to return
                foreach (var photo in flickrPhotos)
                {
                    PhotoList.AppendChild(BuildSinglePhotoXml(photo, doc, flickrSizeMSTB, flickrThumbSizeMSTB));
                }

                return doc.CreateNavigator().Select("/*");
            }
            catch (Exception e)
            {
                // If there's an exception we'll output an error element instead
                XmlDocument errorDoc = new XmlDocument();
                errorDoc.LoadXml(String.Format("<error>{0}</error>", System.Web.HttpUtility.HtmlEncode(e.ToString())));
                return errorDoc.CreateNavigator().Select(".");
            }
        }

        /// <summary>
        /// Use the Flickr API to search for all photos for a full text search of title, tags, and description
        /// </summary>
        /// <param name="searchText">
        /// A free text search. Photos who's title, description or tags contain the text 
        /// will be returned. You can exclude results that match a term by prepending 
        /// it with a - character.
        /// </param>
        /// <param name="flickrSizeMSTB">
        /// s	small square 75x75
        /// t	thumbnail, 100 on longest side
        /// m	small, 240 on longest side
        /// -	medium, 500 on longest side (default)
        /// b	large, 1024 on longest side (only exists for very large original images)
        /// </param>
        /// <param name="flickrThumbSizeMSTB">
        /// s	small square 75x75
        /// t	thumbnail, 100 on longest side
        /// </param>
        /// <param name="numberOfPhotos">Integer. The maximum allowed value is 500.</param>
        /// <param name="flickrSortOrder">The possible values are: date-posted-asc, date-posted-desc, date-taken-asc, date-taken-desc, interestingness-desc (default), interestingness-asc, and relevance</param>
        /// <param name="minTakenDate">Minimum taken date. Photos with an taken date greater than or equal to this value will be returned.</param>
        /// <param name="maxTakenDate">Maximum taken date. Photos with an taken date less than or equal to this value will be returned.</param>
        /// <returns>XML</returns>
        public static XPathNodeIterator ByFreeText(string searchText, string flickrSizeMSTB, string flickrThumbSizeMSTB, int numberOfPhotos, string flickrSortOrder, string minTakenDate, string maxTakenDate)
        {
            try
            {
                //Create XML object
                XmlDocument doc = new XmlDocument();
                XmlElement PhotoList = (XmlElement)doc.AppendChild(doc.CreateElement("PhotoList"));

                // Setup Search
                Flickr flickr = new Flickr();

                PhotoSearchOptions searchOptions = new PhotoSearchOptions();
                searchOptions.Text = searchText;
                searchOptions.SafeSearch = SafetyLevel.Safe;
                searchOptions.PerPage = numberOfPhotos;
                searchOptions.Extras = (PhotoSearchExtras.DateTaken | PhotoSearchExtras.Geo | PhotoSearchExtras.OwnerName | PhotoSearchExtras.Tags | PhotoSearchExtras.Views);
                searchOptions.SortOrder = PhotoSearchSortOrder.InterestingnessDescending;
                if (!string.IsNullOrEmpty(flickrSortOrder))
                {
                    searchOptions.SortOrder = SearchOrderFromString(flickrSortOrder);
                }
                DateTime minTaken;
                if (DateTime.TryParse(minTakenDate, out minTaken))
                {
                    searchOptions.MinTakenDate = minTaken;
                }
                DateTime maxTaken;
                if (DateTime.TryParse(maxTakenDate, out maxTaken))
                {
                    searchOptions.MaxTakenDate = maxTaken;
                }

                // Call Flickr API
                var flickrPhotos = flickr.PhotosSearch(searchOptions);

                // Build XML to return
                foreach (var photo in flickrPhotos)
                {
                    PhotoList.AppendChild(BuildSinglePhotoXml(photo, doc, flickrSizeMSTB, flickrThumbSizeMSTB));
                }

                return doc.CreateNavigator().Select("/*");
            }
            catch (Exception e)
            {
                // If there's an exception we'll output an error element instead
                XmlDocument errorDoc = new XmlDocument();
                errorDoc.LoadXml(String.Format("<error>{0}</error>", System.Web.HttpUtility.HtmlEncode(e.ToString())));
                return errorDoc.CreateNavigator().Select(".");
            }
        }

        /// <summary>
        /// Use the Flickr API to search for all photos for a full text search of title, tags, and description
        /// </summary>
        /// <param name="searchText">
        /// A free text search. Photos who's title, description or tags contain the text 
        /// will be returned. You can exclude results that match a term by prepending 
        /// it with a - character.
        /// </param>
        /// <param name="flickrSizeMSTB">
        /// s	small square 75x75
        /// t	thumbnail, 100 on longest side
        /// m	small, 240 on longest side
        /// -	medium, 500 on longest side (default)
        /// b	large, 1024 on longest side (only exists for very large original images)
        /// </param>
        /// <param name="flickrThumbSizeMSTB">
        /// s	small square 75x75
        /// t	thumbnail, 100 on longest side
        /// </param>
        /// <param name="photosPerPage">Integer. The maximum allowed value is 500.</param>
        /// <param name="page">Integer. The page of results to return.</param>
        /// <param name="flickrSortOrder">The possible values are: date-posted-asc, date-posted-desc, date-taken-asc, date-taken-desc, interestingness-desc (default), interestingness-asc, and relevance</param>
        /// <param name="minTakenDate">Minimum taken date. Photos with an taken date greater than or equal to this value will be returned.</param>
        /// <param name="maxTakenDate">Maximum taken date. Photos with an taken date less than or equal to this value will be returned.</param>
        /// <returns>XML</returns>
        public static XPathNodeIterator ByFreeTextWithPaging(string searchText, string flickrSizeMSTB, string flickrThumbSizeMSTB, int photosPerPage, int page, string flickrSortOrder, string minTakenDate, string maxTakenDate)
        {
            try
            {
                //Create XML object
                XmlDocument doc = new XmlDocument();
                XmlElement PhotoList = (XmlElement)doc.AppendChild(doc.CreateElement("PhotoList"));

                // Setup Search
                Flickr flickr = new Flickr();

                PhotoSearchOptions searchOptions = new PhotoSearchOptions();
                searchOptions.Text = searchText;
                searchOptions.SafeSearch = SafetyLevel.Safe;
                searchOptions.PerPage = photosPerPage;
                searchOptions.Page = page;
                searchOptions.Extras = (PhotoSearchExtras.DateTaken | PhotoSearchExtras.Geo | PhotoSearchExtras.OwnerName | PhotoSearchExtras.Tags | PhotoSearchExtras.Views);
                searchOptions.SortOrder = PhotoSearchSortOrder.InterestingnessDescending;
                if (!string.IsNullOrEmpty(flickrSortOrder))
                {
                    searchOptions.SortOrder = SearchOrderFromString(flickrSortOrder);
                }
                DateTime minTaken;
                if (DateTime.TryParse(minTakenDate, out minTaken))
                {
                    searchOptions.MinTakenDate = minTaken;
                }
                DateTime maxTaken;
                if (DateTime.TryParse(maxTakenDate, out maxTaken))
                {
                    searchOptions.MaxTakenDate = maxTaken;
                }

                // Call Flickr API
                var flickrPhotos = flickr.PhotosSearch(searchOptions);

                // Build XML to return
                foreach (var photo in flickrPhotos)
                {
                    PhotoList.AppendChild(BuildSinglePhotoXml(photo, doc, flickrSizeMSTB, flickrThumbSizeMSTB));
                }

                return doc.CreateNavigator().Select("/*");
            }
            catch (Exception e)
            {
                // If there's an exception we'll output an error element instead
                XmlDocument errorDoc = new XmlDocument();
                errorDoc.LoadXml(String.Format("<error>{0}</error>", System.Web.HttpUtility.HtmlEncode(e.ToString())));
                return errorDoc.CreateNavigator().Select(".");
            }
        }

        /// <summary>
        /// Use the Flickr API to search for all photos by one or more comma separated tags
        /// </summary>
        /// <param name="tagsCommaSeparated">
        /// A comma-delimited list of tags. Photos with one or more of the tags listed will be returned. 
        /// You can exclude results that match a term by prepending it with a - character.
        /// </param>
        /// <param name="tagMode">Either 'any' for an OR combination of tags, or 'all' for an AND combination. Defaults to 'any' if not specified.</param>
        /// <param name="flickrSizeMSTB">
        /// s	small square 75x75
        /// t	thumbnail, 100 on longest side
        /// m	small, 240 on longest side
        /// -	medium, 500 on longest side (default)
        /// b	large, 1024 on longest side (only exists for very large original images)
        /// </param>
        /// <param name="flickrThumbSizeMSTB">
        /// s	small square 75x75
        /// t	thumbnail, 100 on longest side
        /// </param>
        /// <param name="numberOfPhotos">Integer. The maximum allowed value is 500.</param>
        /// <param name="flickrSortOrder">The possible values are: date-posted-asc, date-posted-desc, date-taken-asc, date-taken-desc, interestingness-desc (default), interestingness-asc, and relevance</param>
        /// <param name="minTakenDate">Minimum taken date. Photos with an taken date greater than or equal to this value will be returned.</param>
        /// <param name="maxTakenDate">Maximum taken date. Photos with an taken date less than or equal to this value will be returned.</param>
        /// <returns>XML</returns>
        public static XPathNodeIterator ByTag(string tagsCommaSeparated, string tagMode, string flickrSizeMSTB, string flickrThumbSizeMSTB, int numberOfPhotos, string flickrSortOrder, string minTakenDate, string maxTakenDate)
        {
            try
            {
                //Create XML object
                XmlDocument doc = new XmlDocument();
                XmlElement PhotoList = (XmlElement)doc.AppendChild(doc.CreateElement("PhotoList"));

                // Setup Search
                Flickr flickr = new Flickr();

                PhotoSearchOptions searchOptions = new PhotoSearchOptions();
                searchOptions.Tags = tagsCommaSeparated;
                searchOptions.TagMode = (tagMode == "all" ? TagMode.AllTags : TagMode.AnyTag);
                searchOptions.SafeSearch = SafetyLevel.Safe;
                searchOptions.PerPage = numberOfPhotos;
                searchOptions.Extras = (PhotoSearchExtras.DateTaken | PhotoSearchExtras.Geo | PhotoSearchExtras.OwnerName);
                searchOptions.SortOrder = PhotoSearchSortOrder.InterestingnessDescending;
                if (!string.IsNullOrEmpty(flickrSortOrder))
                {
                    searchOptions.SortOrder = SearchOrderFromString(flickrSortOrder);
                }
                DateTime minTaken;
                if (DateTime.TryParse(minTakenDate, out minTaken))
                {
                    searchOptions.MinTakenDate = minTaken;
                }
                DateTime maxTaken;
                if (DateTime.TryParse(maxTakenDate, out maxTaken))
                {
                    searchOptions.MaxTakenDate = maxTaken;
                }


                // Call Flickr API
                var flickrPhotos = flickr.PhotosSearch(searchOptions);

                // Build XML to return
                foreach (var photo in flickrPhotos)
                {
                    PhotoList.AppendChild( BuildSinglePhotoXml(photo, doc, flickrSizeMSTB, flickrThumbSizeMSTB) );
                }

                return doc.CreateNavigator().Select("/*");
            }
            catch (Exception e)
            {
                // If there's an exception we'll output an error element instead
                XmlDocument errorDoc = new XmlDocument();
                errorDoc.LoadXml(
                    String.Format(
                            "<error><info>{0}</info><stack>{1}</stack></error>", 
                            System.Web.HttpUtility.HtmlEncode(e.ToString()),
                            System.Web.HttpUtility.HtmlEncode(e.StackTrace.ToString())
                        )
                    );
                return errorDoc.CreateNavigator().Select(".");
            }
        }

        /// <summary>
        /// Use the Flickr API to search for all photos by one or more comma separated tags.  This has Paging available to get more than 500 photos.
        /// </summary>
        /// <param name="tagsCommaSeparated">
        /// A comma-delimited list of tags. Photos with one or more of the tags listed will be returned. 
        /// You can exclude results that match a term by prepending it with a - character.
        /// </param>
        /// <param name="tagMode">Either 'any' for an OR combination of tags, or 'all' for an AND combination. Defaults to 'any' if not specified.</param>
        /// <param name="flickrSizeMSTB">
        /// s	small square 75x75
        /// t	thumbnail, 100 on longest side
        /// m	small, 240 on longest side
        /// -	medium, 500 on longest side (default)
        /// b	large, 1024 on longest side (only exists for very large original images)
        /// </param>
        /// <param name="flickrThumbSizeMSTB">
        /// s	small square 75x75
        /// t	thumbnail, 100 on longest side
        /// </param>
        /// <param name="photosPerPage">Integer. The maximum allowed value is 500.</param>
        /// <param name="page">Integer. The page of results to return.</param>
        /// <param name="flickrSortOrder">The possible values are: date-posted-asc, date-posted-desc, date-taken-asc, date-taken-desc, interestingness-desc (default), interestingness-asc, and relevance</param>
        /// <param name="minTakenDate">Minimum taken date. Photos with an taken date greater than or equal to this value will be returned.</param>
        /// <param name="maxTakenDate">Maximum taken date. Photos with an taken date less than or equal to this value will be returned.</param>
        /// <returns>XML</returns>
        public static XPathNodeIterator ByTagWithPaging(string tagsCommaSeparated, string tagMode, string flickrSizeMSTB, string flickrThumbSizeMSTB, int photosPerPage, int page, string flickrSortOrder, string minTakenDate, string maxTakenDate)
        {
            try
            {
                //Create XML object
                XmlDocument doc = new XmlDocument();
                XmlElement PhotoList = (XmlElement)doc.AppendChild(doc.CreateElement("PhotoList"));

                // Setup Search
                Flickr flickr = new Flickr();

                PhotoSearchOptions searchOptions = new PhotoSearchOptions();
                searchOptions.Tags = tagsCommaSeparated;
                searchOptions.TagMode = (tagMode == "all" ? TagMode.AllTags : TagMode.AnyTag);
                searchOptions.SafeSearch = SafetyLevel.Safe;
                searchOptions.PerPage = photosPerPage;
                searchOptions.Page = page;
                searchOptions.Extras = (PhotoSearchExtras.DateTaken | PhotoSearchExtras.Geo | PhotoSearchExtras.OwnerName);
                searchOptions.SortOrder = PhotoSearchSortOrder.InterestingnessDescending;
                if (!string.IsNullOrEmpty(flickrSortOrder))
                {
                    searchOptions.SortOrder = SearchOrderFromString(flickrSortOrder);
                }
                DateTime minTaken;
                if (DateTime.TryParse(minTakenDate, out minTaken))
                {
                    searchOptions.MinTakenDate = minTaken;
                }
                DateTime maxTaken;
                if (DateTime.TryParse(maxTakenDate, out maxTaken))
                {
                    searchOptions.MaxTakenDate = maxTaken;
                }


                // Call Flickr API
                var flickrPhotos = flickr.PhotosSearch(searchOptions);

                // Build XML to return
                foreach (var photo in flickrPhotos)
                {
                    PhotoList.AppendChild(BuildSinglePhotoXml(photo, doc, flickrSizeMSTB, flickrThumbSizeMSTB));
                }

                return doc.CreateNavigator().Select("/*");
            }
            catch (Exception e)
            {
                // If there's an exception we'll output an error element instead
                XmlDocument errorDoc = new XmlDocument();
                errorDoc.LoadXml(
                    String.Format(
                            "<error><info>{0}</info><stack>{1}</stack></error>",
                            System.Web.HttpUtility.HtmlEncode(e.ToString()),
                            System.Web.HttpUtility.HtmlEncode(e.StackTrace.ToString())
                        )
                    );
                return errorDoc.CreateNavigator().Select(".");
            }
        }

        /// <summary>
        /// Use the Flickr API to search for all photos by one or more comma separated tags for a user
        /// </summary>
        /// <param name="flickrUserId">User Id from Flickr (i.e. 12345678@N12)</param>
        /// <param name="tagsCommaSeparated">
        /// A comma-delimited list of tags. Photos with one or more of the tags listed will be returned. 
        /// You can exclude results that match a term by prepending it with a - character.
        /// </param>
        /// <param name="tagMode">Either 'any' for an OR combination of tags, or 'all' for an AND combination. Defaults to 'any' if not specified.</param>
        /// <param name="flickrSizeMSTB">
        /// s	small square 75x75
        /// t	thumbnail, 100 on longest side
        /// m	small, 240 on longest side
        /// -	medium, 500 on longest side (default)
        /// b	large, 1024 on longest side (only exists for very large original images)
        /// </param>
        /// <param name="flickrThumbSizeMSTB">
        /// s	small square 75x75
        /// t	thumbnail, 100 on longest side
        /// </param>
        /// <param name="numberOfPhotos">Integer. The maximum allowed value is 500.</param>
        /// <param name="flickrSortOrder">The possible values are: date-posted-asc, date-posted-desc, date-taken-asc, date-taken-desc, interestingness-desc (default), interestingness-asc, and relevance</param>
        /// <param name="minTakenDate">Minimum taken date. Photos with an taken date greater than or equal to this value will be returned.</param>
        /// <param name="maxTakenDate">Maximum taken date. Photos with an taken date less than or equal to this value will be returned.</param>
        /// <returns>XML</returns>
        public static XPathNodeIterator ByUserAndTag(string flickrUserId, string tagsCommaSeparated, string tagMode, string flickrSizeMSTB, string flickrThumbSizeMSTB, int numberOfPhotos, string flickrSortOrder, string minTakenDate, string maxTakenDate)
        {
            try
            {
                //Create XML object
                XmlDocument doc = new XmlDocument();
                XmlElement PhotoList = (XmlElement)doc.AppendChild(doc.CreateElement("PhotoList"));

                // Setup Search
                Flickr flickr = new Flickr();

                PhotoSearchOptions searchOptions = new PhotoSearchOptions();
                searchOptions.UserId = flickrUserId;
                searchOptions.Tags = tagsCommaSeparated;
                searchOptions.TagMode = (tagMode == "all" ? TagMode.AllTags : TagMode.AnyTag);
                searchOptions.SafeSearch = SafetyLevel.Safe;
                searchOptions.PerPage = numberOfPhotos;
                searchOptions.Extras = (PhotoSearchExtras.DateTaken | PhotoSearchExtras.Geo | PhotoSearchExtras.OwnerName);
                searchOptions.SortOrder = PhotoSearchSortOrder.InterestingnessDescending;
                if (!string.IsNullOrEmpty(flickrSortOrder))
                {
                    searchOptions.SortOrder = SearchOrderFromString(flickrSortOrder);
                }
                DateTime minTaken;
                if (DateTime.TryParse(minTakenDate, out minTaken))
                {
                    searchOptions.MinTakenDate = minTaken;
                }
                DateTime maxTaken;
                if (DateTime.TryParse(maxTakenDate, out maxTaken))
                {
                    searchOptions.MaxTakenDate = maxTaken;
                }


                // Call Flickr API
                var flickrPhotos = flickr.PhotosSearch(searchOptions);

                // Build XML to return
                foreach (var photo in flickrPhotos)
                {
                    PhotoList.AppendChild( BuildSinglePhotoXml(photo, doc, flickrSizeMSTB, flickrThumbSizeMSTB) );
                }

                return doc.CreateNavigator().Select("/*");
            }
            catch (Exception e)
            {
                // If there's an exception we'll output an error element instead
                XmlDocument errorDoc = new XmlDocument();
                errorDoc.LoadXml(
                    String.Format(
                            "<error><info>{0}</info><stack>{1}</stack></error>", 
                            System.Web.HttpUtility.HtmlEncode(e.ToString()),
                            System.Web.HttpUtility.HtmlEncode(e.StackTrace.ToString())
                        )
                    );
                return errorDoc.CreateNavigator().Select(".");
            }
        }

        /// <summary>
        /// Use the Flickr API to search for all photos by one or more comma separated tags for a user.  This has Paging available to get more than 500 photos.
        /// </summary>
        /// <param name="flickrUserId">User Id from Flickr (i.e. 12345678@N12)</param>
        /// <param name="tagsCommaSeparated">
        /// A comma-delimited list of tags. Photos with one or more of the tags listed will be returned. 
        /// You can exclude results that match a term by prepending it with a - character.
        /// </param>
        /// <param name="tagMode">Either 'any' for an OR combination of tags, or 'all' for an AND combination. Defaults to 'any' if not specified.</param>
        /// <param name="flickrSizeMSTB">
        /// s	small square 75x75
        /// t	thumbnail, 100 on longest side
        /// m	small, 240 on longest side
        /// -	medium, 500 on longest side (default)
        /// b	large, 1024 on longest side (only exists for very large original images)
        /// </param>
        /// <param name="flickrThumbSizeMSTB">
        /// s	small square 75x75
        /// t	thumbnail, 100 on longest side
        /// </param>
        /// <param name="photosPerPage">Integer. The maximum allowed value is 500.</param>
        /// <param name="page">Integer. The page of results to return.</param>
        /// <param name="flickrSortOrder">The possible values are: date-posted-asc, date-posted-desc, date-taken-asc, date-taken-desc, interestingness-desc (default), interestingness-asc, and relevance</param>
        /// <param name="minTakenDate">Minimum taken date. Photos with an taken date greater than or equal to this value will be returned.</param>
        /// <param name="maxTakenDate">Maximum taken date. Photos with an taken date less than or equal to this value will be returned.</param>
        /// <returns>XML</returns>
        public static XPathNodeIterator ByUserAndTagWithPaging(string flickrUserId, string tagsCommaSeparated, string tagMode, string flickrSizeMSTB, string flickrThumbSizeMSTB, int photosPerPage, int page, string flickrSortOrder, string minTakenDate, string maxTakenDate)
        {
            try
            {
                //Create XML object
                XmlDocument doc = new XmlDocument();
                XmlElement PhotoList = (XmlElement)doc.AppendChild(doc.CreateElement("PhotoList"));

                // Setup Search
                Flickr flickr = new Flickr();

                PhotoSearchOptions searchOptions = new PhotoSearchOptions();
                searchOptions.UserId = flickrUserId;
                searchOptions.Tags = tagsCommaSeparated;
                searchOptions.TagMode = (tagMode == "all" ? TagMode.AllTags : TagMode.AnyTag);
                searchOptions.SafeSearch = SafetyLevel.Safe;
                searchOptions.PerPage = photosPerPage;
                searchOptions.Page = page;
                searchOptions.Extras = (PhotoSearchExtras.DateTaken | PhotoSearchExtras.Geo | PhotoSearchExtras.OwnerName);
                searchOptions.SortOrder = PhotoSearchSortOrder.InterestingnessDescending;
                if (!string.IsNullOrEmpty(flickrSortOrder))
                {
                    searchOptions.SortOrder = SearchOrderFromString(flickrSortOrder);
                }
                DateTime minTaken;
                if (DateTime.TryParse(minTakenDate, out minTaken))
                {
                    searchOptions.MinTakenDate = minTaken;
                }
                DateTime maxTaken;
                if (DateTime.TryParse(maxTakenDate, out maxTaken))
                {
                    searchOptions.MaxTakenDate = maxTaken;
                }


                // Call Flickr API
                var flickrPhotos = flickr.PhotosSearch(searchOptions);

                // Build XML to return
                foreach (var photo in flickrPhotos)
                {
                    PhotoList.AppendChild(BuildSinglePhotoXml(photo, doc, flickrSizeMSTB, flickrThumbSizeMSTB));
                }

                return doc.CreateNavigator().Select("/*");
            }
            catch (Exception e)
            {
                // If there's an exception we'll output an error element instead
                XmlDocument errorDoc = new XmlDocument();
                errorDoc.LoadXml(
                    String.Format(
                            "<error><info>{0}</info><stack>{1}</stack></error>",
                            System.Web.HttpUtility.HtmlEncode(e.ToString()),
                            System.Web.HttpUtility.HtmlEncode(e.StackTrace.ToString())
                        )
                    );
                return errorDoc.CreateNavigator().Select(".");
            }
        }

        /// <summary>
        /// Use the Flickr API to search for all photos in a set
        /// </summary>
        /// <param name="photoSetId">The id of the photoset to return the photos for.</param>
        /// <param name="numberOfPhotosPerPage">Integer. The maximum allowed value is 500.</param>
        /// <param name="page">Integer. The page of results to return.</param>
        /// <param name="flickrSizeMSTB">
        /// s	small square 75x75
        /// t	thumbnail, 100 on longest side
        /// m	small, 240 on longest side
        /// -	medium, 500 on longest side (default)
        /// b	large, 1024 on longest side (only exists for very large original images)
        /// </param>
        /// <param name="flickrThumbSizeMSTB">
        /// s	small square 75x75
        /// t	thumbnail, 100 on longest side
        /// </param>
        /// <returns>XML</returns>
        public static XPathNodeIterator BySet(string photoSetId, int numberOfPhotosPerPage, int page, string flickrSizeMSTB, string flickrThumbSizeMSTB)
        {
            try
            {
                //Create XML object
                XmlDocument doc = new XmlDocument();
                XmlElement PhotoList = (XmlElement)doc.AppendChild(doc.CreateElement("PhotoList"));

                // Setup Search
                Flickr flickr = new Flickr();

                // Call Flickr API
                var flickrPhotoset = flickr.PhotosetsGetPhotos(photoSetId,
                                                    (PhotoSearchExtras.DateTaken | PhotoSearchExtras.Geo | PhotoSearchExtras.OwnerName),
                                                    page,
                                                    numberOfPhotosPerPage);

                // Build XML to return
                foreach (var photo in flickrPhotoset)
                {
                    PhotoList.AppendChild(BuildSinglePhotoXml(photo, doc, flickrSizeMSTB, flickrThumbSizeMSTB));
                }

                return doc.CreateNavigator().Select("/*");
            }
            catch (Exception e)
            {
                // If there's an exception we'll output an error element instead
                XmlDocument errorDoc = new XmlDocument();
                errorDoc.LoadXml(
                    String.Format(
                            "<error><info>{0}</info><stack>{1}</stack></error>",
                            System.Web.HttpUtility.HtmlEncode(e.ToString()),
                            System.Web.HttpUtility.HtmlEncode(e.StackTrace.ToString())
                        )
                    );
                return errorDoc.CreateNavigator().Select(".");
            }
        }

        /// <summary>
        /// Gets photosets for the specified user.
        /// </summary>
        /// <param name="userId">The NSID of the user to get a photoset list for.</param>
        /// <param name="photosetPhotoSize">Size of the photoset photo.
        /// s - Small square 75x75
        /// t - Thumbnail, 100 on longest side
        /// m - Small, 240 on longest side
        ///   - medium, 500 on longest side (default)
        /// b - large, 1024 on longest side (only exists for very large original images)
        /// </param>
        /// <param name="photosetThumbnailSize">Size of the photoset thumbnail.
        /// s - small square 75x75
        /// t - thumbnail, 100 on longest side
        /// </param>
        /// <returns>
        /// Returns the photosets belonging to the specified user.
        /// </returns>
        /// <example>GetPhotoSets("53054828@N00")</example>
        public static XPathNodeIterator GetPhotosets(string userId, string photosetPhotoSize, string photosetThumbnailSize)
        {
            // Create XML object
            var doc = new XmlDocument();
            var photosetsNode = doc.AppendChild(doc.CreateElement("photosets"));

            // Create an instance of the FlickrNet API
            var flickr = new Flickr();

            // Get a list of Photosets for the specified user
            var photosets = flickr.PhotosetsGetList(userId);

            // Iterate over the photosets in the collection
            foreach (var set in photosets)
            {
                var photoset = set;

                // Create a new photoset node
                var photosetNode = doc.CreateElement("photoset");

                // Create and add attributes to node
                var photosetAttributeId = doc.CreateAttribute("id");
                photosetAttributeId.Value = photoset.PhotosetId;
                photosetNode.Attributes.Append(photosetAttributeId);

                var photosetAttributePrimaryId = doc.CreateAttribute("primary");
                photosetAttributePrimaryId.Value = photoset.PrimaryPhotoId;
                photosetNode.Attributes.Append(photosetAttributePrimaryId);

                var photosetAttributeSecretId = doc.CreateAttribute("secret");
                photosetAttributeSecretId.Value = photoset.Secret;
                photosetNode.Attributes.Append(photosetAttributeSecretId);

                var photosetAttributeServer = doc.CreateAttribute("server");
                photosetAttributeServer.Value = photoset.Server;
                photosetNode.Attributes.Append(photosetAttributeServer);

                var photosetAttributeFarm = doc.CreateAttribute("farm");
                photosetAttributeFarm.Value = photoset.Farm;
                photosetNode.Attributes.Append(photosetAttributeFarm);

                var photosetAttributePhotos = doc.CreateAttribute("photos");
                photosetAttributePhotos.Value = photoset.NumberOfPhotos.ToString();
                photosetNode.Attributes.Append(photosetAttributePhotos);

                var titleNode = doc.CreateElement("title");
                titleNode.InnerText = photoset.Title;
                photosetNode.AppendChild(titleNode);

                var descriptionNode = doc.CreateElement("description");
                descriptionNode.InnerText = photoset.Description;
                photosetNode.AppendChild(descriptionNode);

                var urlNode = doc.CreateElement("url");
                urlNode.InnerText = photoset.Url;
                photosetNode.AppendChild(urlNode);

                photosetsNode.AppendChild(photosetNode);

                var photo = flickr.PhotosetsGetPhotos(photoset.PhotosetId).Where(p => p.PhotoId == photoset.PrimaryPhotoId).FirstOrDefault();
                photosetNode.AppendChild(BuildSinglePhotoXml(photo, doc, photosetPhotoSize, photosetThumbnailSize));
            }

            return doc.CreateNavigator().Select("/*");
        }

        /// <summary>
        /// Gets the photoset photos.
        /// </summary>
        /// <param name="photosetId">The photoset id.</param>
        /// <param name="photoSize">Size of the photo.
        /// s - Small square 75x75
        /// t - Thumbnail, 100 on longest side
        /// m - Small, 240 on longest side
        ///   - medium, 500 on longest side (default)
        /// b - large, 1024 on longest side (only exists for very large original images)
        /// </param>
        /// <param name="thumbnailSize">Size of the thumbnail.
        /// s - small square 75x75
        /// t - thumbnail, 100 on longest side
        /// </param>
        /// <returns>Photos in the requested photoset</returns>
        public static XPathNodeIterator GetPhotosetPhotos(string photosetId, string photoSize, string thumbnailSize)
        {
            // Create an instance of the FlickrNet API
            var flickr = new Flickr();

            // Create XML object
            var doc = new XmlDocument();

            // Create a photoset node
            var photosetNode = doc.CreateElement("photoset");

            var photoset = flickr.PhotosetsGetInfo(photosetId);

            // Create and populate a new node with the title of the photoset
            var photosetTitleNode = doc.CreateElement("title");
            photosetTitleNode.InnerText = photoset.Title;

            // Append the photosetTitleNode to the photosetNode
            photosetNode.AppendChild(photosetTitleNode);

            // Create and populate a new node with the title of the photoset
            var photosetDescriptionNode = doc.CreateElement("description");
            photosetDescriptionNode.InnerText = photoset.Description;

            // Append the photosetTitleNode to the photosetNode
            photosetNode.AppendChild(photosetDescriptionNode);

            // Get photos in the set
            var photos = flickr.PhotosetsGetPhotos(photosetId);

            // Iterate over the photos in the set
            foreach (var photosetPhoto in photos)
            {
                var photo = photosetPhoto;

                // Add new nodes for each photo in the set
                photosetNode.AppendChild(BuildSinglePhotoXml(photo, doc, photoSize, thumbnailSize));
            }

            doc.AppendChild(photosetNode);

            return doc.CreateNavigator().Select("/*");
        }

        /// <summary>
        /// Helper to build xml for a single photo
        /// </summary>
        /// <param name="photo"></param>
        /// <param name="doc"></param>
        /// <param name="flickrSizeMSTB">
        /// s	small square 75x75
        /// t	thumbnail, 100 on longest side
        /// m	small, 240 on longest side
        /// -	medium, 500 on longest side (default)
        /// b	large, 1024 on longest side (only exists for very large original images)
        /// </param>
        /// <param name="flickrThumbSizeMSTB">
        /// s	small square 75x75
        /// t	thumbnail, 100 on longest side
        /// </param>
        /// <returns></returns>
        static private XmlElement BuildSinglePhotoXml(Photo photo, XmlDocument doc, string flickrSizeMSTB, string flickrThumbSizeMSTB)
        {            
            var elem = doc.CreateElement("Photo");

            // Photo Title
            var title = doc.CreateAttribute("Title", string.Empty);
            title.Value = photo.Title;
            elem.Attributes.Append(title);

            // Photo URL to Large Image Location
            var mainImage = doc.CreateAttribute("ImageFile");
            if (String.IsNullOrEmpty(flickrSizeMSTB))
            {
                mainImage.Value = String.Format("http://farm{0}.static.flickr.com/{1}/{2}_{3}.jpg", photo.Farm, photo.Server, photo.PhotoId, photo.Secret);
            }
            else if (flickrSizeMSTB.Length == 1)
            {
                mainImage.Value = String.Format("http://farm{0}.static.flickr.com/{1}/{2}_{3}_{4}.jpg", photo.Farm, photo.Server, photo.PhotoId, photo.Secret, flickrSizeMSTB);
            }

            elem.Attributes.Append(mainImage);

            // Create thumbnail image attributes
            var thumbImage = doc.CreateAttribute("Thumbnail");
            var thumbImageWidth = doc.CreateAttribute("ThumbnailWidth");
            var thumbImageHeight = doc.CreateAttribute("ThumbnailHeight");

            if (String.IsNullOrEmpty(flickrThumbSizeMSTB))
            {
                thumbImage.Value = String.Format("http://farm{0}.static.flickr.com/{1}/{2}_{3}_t.jpg", photo.Farm, photo.Server, photo.PhotoId, photo.Secret);
                thumbImageWidth.Value = photo.ThumbnailWidth.HasValue ? photo.ThumbnailWidth.ToString() : String.Empty;
                thumbImageHeight.Value = photo.ThumbnailHeight.HasValue ? photo.ThumbnailHeight.ToString() : String.Empty;
            }
            else if (flickrThumbSizeMSTB.Length == 1)
            {
                thumbImage.Value = String.Format("http://farm{0}.static.flickr.com/{1}/{2}_{3}_{4}.jpg", photo.Farm, photo.Server, photo.PhotoId, photo.Secret, flickrThumbSizeMSTB);
                thumbImageWidth.Value = photo.SquareThumbnailWidth.HasValue ? photo.SquareThumbnailWidth.ToString() : String.Empty;
                thumbImageHeight.Value = photo.SquareThumbnailHeight.HasValue ? photo.SquareThumbnailHeight.ToString() : String.Empty;
            }

            // Append the thumbnail attribute to the Photo node
            elem.Attributes.Append(thumbImage);

            // URL to Flickr Page
            var flickrUrl = doc.CreateAttribute("FlickrPageURL");
            flickrUrl.Value = String.Format("http://www.flickr.com/photos/{0}/{1}", photo.UserId, photo.PhotoId);
            elem.Attributes.Append(flickrUrl);

            // Person to Credit
            var userName = doc.CreateAttribute("OwnerName");
            userName.Value = photo.OwnerName;
            elem.Attributes.Append(userName);

            // Lat
            var latitude = doc.CreateAttribute("Latitude");
            latitude.Value = photo.Latitude.ToString();
            elem.Attributes.Append(latitude);

            // Long
            var longitude = doc.CreateAttribute("Longitude");
            longitude.Value = photo.Longitude.ToString();
            elem.Attributes.Append(longitude);

            // Date Taken
            var dateTaken = doc.CreateAttribute("DateTaken");
            dateTaken.Value = photo.DateTaken.ToString("yyyy/MM/dd");
            elem.Attributes.Append(dateTaken);

            // Tags
            var tags = doc.CreateAttribute("Tags");
            tags.Value = String.Join(",", photo.Tags.ToArray());
            elem.Attributes.Append(tags);

            // Views
            var views = doc.CreateAttribute("Views", string.Empty);
            views.Value = photo.Views.ToString();
            elem.Attributes.Append(views);

            return elem;
        }

        /// <summary>
        /// Gets the matching PhotoSearchSortOrder enumerator based on the string passed into the method
        /// </summary>
        /// <param name="flickrSortOrder">The flickr sort order.</param>
        /// <returns>he matching PhotoSearchSortOrder enumerator</returns>
        private static PhotoSearchSortOrder SearchOrderFromString(string flickrSortOrder)
        {
            var retOrder = PhotoSearchSortOrder.InterestingnessDescending;

            switch (flickrSortOrder)
            {  
                case "date-posted-asc":
                    retOrder = PhotoSearchSortOrder.DatePostedAscending;
                    break;

                case "date-posted-desc":
                    retOrder = PhotoSearchSortOrder.DatePostedDescending;
                    break;

                case "date-taken-asc":
                    retOrder = PhotoSearchSortOrder.DateTakenAscending;
                    break;

                case "date-taken-desc":
                    retOrder = PhotoSearchSortOrder.DateTakenDescending;
                    break;

                case "interestingness-desc":
                    retOrder = PhotoSearchSortOrder.InterestingnessDescending;
                    break;

                case "interestingness-asc":
                    retOrder = PhotoSearchSortOrder.InterestingnessAscending;
                    break;

                case "relevance":
                    retOrder = PhotoSearchSortOrder.Relevance;
                    break;
            }

            return retOrder;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="relativeDirectory"></param>
        /// <returns></returns>
        public static string DirectoryLocation(string relativeDirectory)
        {
            string directory = System.Web.HttpContext.Current.Server.MapPath(relativeDirectory);

            return directory;
        }
    }
}
